package com.brayan.webapp.service.general.geoinfo;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.ejb.Singleton;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Invocation.Builder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;

import org.apache.log4j.Logger;

import com.brayan.webapp.model.general.geoinfo.GeoInfo;

@Singleton
public class GeoIPBean {

	private static Logger LOGGER = Logger.getLogger(GeoIPBean.class);

	private static final String IPV4_PATTERN = "^(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";

	Map<String, GeoInfo> geoInfoCache = new HashMap<String, GeoInfo>();
	// Service Description is here http://freegeoip.net/
	static final String GEO_SERICE_URL = "http://freegeoip.net/";
	static final String FORMAT = "json";

	public GeoInfo getGeoInfoByIp(String ipAddress) {
		final String FAKE_IP = "80.218.114.61";
		final String LOCAL_IP = "127.0.0.1";
		
		if (!isValidIp(ipAddress)) {
			LOGGER.error("Cannot request geo information because IP Address in invalid: "
					+ ipAddress);
			return null;
		}
		
		if(ipAddress.equals(LOCAL_IP)){
			LOGGER.warn(LOCAL_IP + " is translated to the fake IP address " + FAKE_IP);
			ipAddress = FAKE_IP;
		}

		GeoInfo geoInfo = geoInfoCache.get(ipAddress);
		if (geoInfo == null) {
			String uri = GEO_SERICE_URL + FORMAT + "/" + ipAddress;
			LOGGER.debug("IP address " + ipAddress
					+ " is not in local cache. Sending request to " + uri);
			Client client = ClientBuilder.newClient();
			// Invoke the service.			
			WebTarget webTarget = client.target(uri);
			// geoInfo
			Builder builder = webTarget.request(MediaType.APPLICATION_JSON);
			try {
				geoInfo = builder.get(GeoInfo.class);
				// Add to cache.
				geoInfoCache.put(ipAddress, geoInfo);
			} catch (Exception ex) {
				LOGGER.error("Failed to retrieve geo information from request URI "
						+ uri + ". Error: " + ex.getMessage());
				return null;
			}
		} else {
			LOGGER.info("Having this IP address " + ipAddress
					+ " in the cache. ");
		}
		return geoInfo;
	}

	public static boolean isValidIp(String ipAddress) {
		if (ipAddress == null)
			return false;
		Pattern pattern = Pattern.compile(IPV4_PATTERN);
		Matcher matcher = pattern.matcher(ipAddress);
		return matcher.matches();
	}
	
}
